<?php
/**
 * CF_processor2 is a class to simplfy processing of Databse CRUD (Create Remove Update Delete) Tables
 *
 * @package CreateFast
 */

 class CF_ProcessorBase {
 
	 // main variables 
	 var $operation;
	 var $is_ajax;
	var $trigger_param = 'sel';
	var $trigger = '';
	var $trigger_value;
	 var $name;
	 var $filters;
	 
	 var $fieldspec;
	 
	 public $keyvarslist = array();
	 public $colvarslist = array();
	 
 	/**
	* $newvalues
	* Array of new-pair arrays, of form:
	* $newvalues[i][<col_name>] = [value]
	* for all single transactions, i = 0.  for multiple, there is one row for each to be changed
	* rows (i) coorespond to the keys specified in $keyvalues
	*/
	var $newvalues;

	/**
	* $oldvalues
	* Array of old-pair arrays, mostly for detecting change of underlying model vs client.
	* $oldvalues[i][<col_name>] = [value]
	* for all single transactions, i = 0.  for multiple, there is one row for each to be changed
	* rows (i) coorespond to the keys specified in $newvalues
	*/	
 	var $oldvalues;
	/**
	* $keyvalues
	* Array of key-pair arrays, of form:
	* $keyvalues[i][<col_name>] = [value]
	* for all single transactions, i = 0.  for multiple, there is one row for each to be changed
	* rows (i) coorespond to the keys specified in $newvalues
	*/	
 	var $keyvalues;
	
	// prefixes:  These strings may be prepended to request parameters to avoid collision
	var $prefix_new;
	var $prefix_old = 'OV';
	var $prefix_key;
	var $prefix_ctl;
	
	public $op_parameter = 'mode';
	
	var $default_op = 'list';

	// Processing Status variables
	var $is_error = false;
	var $status;

	// used inside functions
	var $set_delimiter = ';';
	var $value_delimiter = ',';
	
	// Generic Get / Set functions --------------------
	function set_fieldspec($thespec){
		$this->fieldspec = $thespec;
	}	

	// Sets name for processor / CRUD set module
	function set_name($name){
		$this->name = $name;

	}	
	// sets the trigger (trigger parameter defined in trigger_param) to trigger 
	// module actions (except for default)
	function set_trigger($trigger){
		$this->trigger = $name;	
	}
	
	// Set the default mode, in case nothing is provided or trigger not activated
	function set_default_op($default_op){
		$this->default_op = $default_op; 
	}
	
	function set_maintable($thetablename){
		$this->maintable = $thetablename;
	}	
	function __construct($thespec = '', $name = ''){
		$this->fieldspec = $thespec;
		//$this->prefix_old = 'OV';
		//$this->op_parameter = 'mode';
		//print 'Constructor run';
		$this->name = $name;
		$this->trigger = $name;
	}
	
	// Request Paremeter functions --------------------
	function GetReqIsAjax(){
		if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'){
			$this->is_ajax = true;
		}
		else{
			$this->is_ajax = false;
		}	
	}
	
	// Checked ok
	function GetReqOp(){
		if(!empty($_REQUEST[$this->op_parameter])){
			$this->operation = $_REQUEST[$this->op_parameter];
		}else{
			$this->operation = $this->default_op;
		}
		return $this->operation;
		print $this->operaiton;
		exit;
	}


	function GetReqTrigger(){
		$this->trigger_value = $_REQUEST[$this->trigger_param];
		return $this->trigger_value;
	}	

/* Value set Population functions
The functions below can be used to populate any of the valuesets properties of the class
These include:
$newvalues:  used for new values for crud operations, 
$keyvalues:  Meant to specify keys to direct which data to operate on
$oldvalues: Meant to recive the 'before' value sent from forms (to detect concurrent changes)
$ctlvalues: (not yet) Meant to recieve a list of other values for control on the sets

Each value set has the form:
$<valueset> [<rownum>] [<variable name>] = <value>
<rownum> starts at 0.  Single rows are still arrays, but only use the 0 element
For changes to multiple value sets, each row is processed  

Two ways of passing values (supported so far):
By named parameter (?variable1=value1&variable2=value2)
By Packed Parameter (?variables=varable1,variable2&values=value1,value2)

Named parameters:  These can be used to pass single values sets.
Prefixes can be used when passin the same variable for different purposes:
For instance, in a CRUD operation, change the Employee_ID to 20 for the record with Employee_id = 10
would have Employee_id variable twice, unless we use a prefix.
In this example, the prefix 'nv_' is used on the new value, and none is used for the key value:
doaction.php?mode=save&Employee_ID=10&nv_Employee_id=20.....
prefixes for the value sets can be set in the variables: prefix_new, prefix_old, prefix_key, prefix_ctl
only prefix_old is set by default, to 'OV'




Packed Parameters:  these can be used to pass single value or multiple value sets.
Values are repersented by strings delimited by commas (or another character)
the Request parameter with the values is $ValParam
The Request parameter of variable names is $VarParam
The delimiter is default to comma (,) for values, and a semicolon (;) for sets
For single value sets, GetPackedParamValues($VarParam, $ValParam) function is used
For Multiple value sets, the $ValParam contains semicolon (or other character) delimited
sets of single value sets.  Multiple value sets use GetPackedParamSets($VarParam, $ValParam)

Standard Flow with the $opspec array:
Standard flow is as such

   START
    |
	
	
	

*/


	function GetReqFilters(){
	
		$flt = new CF_FilterQueryBase($this->fieldspec);
		
		$this->filters = $flt->get_filter_vals();
	
	}

	
	
	// Checked ok
		function GetReqParamsByList($list,$prefix = '',$requireall = false){
			$foundall = true;
			foreach ($list as $col_name){
				if((isset($_REQUEST[$prefix . $col_name])) AND ($_REQUEST[$prefix . $col_name] != '') ){
					$result[0][$col_name] = $_REQUEST[$prefix .$col_name];
					}else{
					   $foundall = false;
					}
				}
			if($requireall){
				if($foundall){
					return $result;
				}else{

					return false;
				}			
			}else{
				return $result;
			}
		}
		
	// Checked OK
	function GetPackedParamValues($VarParam, $ValParam){
		if (isset($_REQUEST[$ValParam])) {
			$strValues = $_REQUEST[$ValParam];
			$arValues = explode($this->value_delimiter, $strValues);
			$proceed = true;
			}
		else {
			$proceed = false;
		}
		
		if (isset($_REQUEST[$VarParam])) {
			$strVariables = $_REQUEST[$VarParam];
			$arVariables = explode($this->value_delimiter, $strVariables);
		}
		else {
			$strVariables = 0;
			$proceed = false;
		}
		// Assign the value for each key variable into the $keyvalues array (position 0 since only one row specified)
		if($proceed){
			foreach($arVariables AS $index=>$keyvar){
				$keyval = $arValues[$index];
				$resultline[$keyvar] = $keyval;
				//print "KEY $keyvar = $keyval \n";
			}
			$result[0] = $resultline;
			return $result;
		}				
	}
	
	//Checked OK
	function GetSingleValue($varParam = 'var',$valParam = 'value'){
			$changecol = $_REQUEST[$varParam];
			$changevalue = $_REQUEST[$valParam];
			$result[0][$changecol] = $changevalue;
			return $result;
	}
	
	// Checked OK
	function GetPackedParamSets($VarParam, $SetParam){
		$dochange = false;
		if(!empty($_REQUEST[$SetParam]) OR $_REQUEST[$SetParam] === 0){
			// Check for the variable order, in the comma list 'VarParam'
			if (isset($_REQUEST[$VarParam])) {
				$strVariables = $_REQUEST[$VarParam];
				$arVariables = explode($this->value_delimiter, $strVariables);
			}
			else {
				//$strVariables = 0;
				$executequery = false;
			}	
			// produce an array ordering key variables
			foreach($arVariables AS $orderindex=>$keyvar){
				$keyorder[$orderindex] = $keyvar;
			}
			// split up sets of key values and assign to 
			$arSets = explode($this->set_delimiter, $_REQUEST[$SetParam]);
	        foreach($arSets AS $setindex=>$arTheSet){
				$arValues = explode($this->value_delimiter, $arTheSet);
	            foreach($arValues AS $keyindex=>$keyvalue){
						$keyval = $keyorder[$keyindex];
						$valueset[$keyval] = $keyvalue;
	                }
				$result[] = $valueset;	
	            }
				return $result;
		} // multikey element is not empty	
	}

	// For the case where multiple lines (identified by a key set) are filled to the same newvalues
	function FillKeysToNewVals(){
		foreach($this->keyvalues AS $i->$thisline){
			$this->newvalues[$i] = $this->newvalues[0];
		}
	}

	
		// If any of the keys on TargetList are not in $LimitList, unset them.
		function FilterByList(&$TargetList, $LimitList){
			$FlipList = array_flip($LimitList);
			foreach($TargetList AS $key => $item){
				if (!isset($FlipList[$key])){
					unset($TargetList[$key]);
				}
			}
		}
		// chck that all elements specified by $LimitList appear as keys in $TargetList
		function CheckArrayComplete($TargetList, $LimitList){
			foreach($LimitList AS $item){
				if(!isset($TargetList[$item])){
					return false;
				}
			}
			return true;
		}
	
		
	
	// Specific
	
	// returns list for keys and columns out of fieldspec
	function ProcessFieldSpec(){

		foreach ($this->fieldspec as $col_name => $colspec){

			$this->colvarslist[]=$col_name;

			if(!empty($colspec['key'])){
				$this->keyvarslist[] = $col_name;

			}
			
		}
	}
// --------------------- Default (no op) functions for override
		function clean_keyvalues(){}
		function clean_newvalues(){}
		function clean_oldvalues(){}
		function clean_ctlvalues(){}
		
		function on_pre_action(){}
		function on_post_action(){}
		function authorize(){ return true;}
		
		function unauthorized(){
			$this->status = 'UnAuthorized';
			$this->is_error = true;
		}
		

 // -------------------- Action  Processor --------------------
 // main dispatch function	
	
	function do_actions(){
		$this->Run();
	}
	
	
	function Run(){
	
		$this->ProcessFieldSpec();
		//print 'show keyarslist <br />';
		//print_r($this->keyvarslist);
		//print 'show colvarslist <br />';
		//print_r($this->colvarslist);
		
		
		if(isset($_REQUEST[$this->trigger_param])  && $_REQUEST[$this->trigger_param] != $this->trigger ){
			return;
		}
		
		$this->GetReqTrigger();
		//print "TRIGGER VALUE = trigger?:  $this->trigger_value  = $this->trigger |";
		// Since this defaults to '' this evaluates true if trigger not sent.  Might change this behaviour
		if($this->trigger_value == $this->trigger){
		//	print 'triggered';
			$mode = $this->GetReqOp();
		}else{
			$mode = $this->default_op;
		}
		
		if(empty($mode)){
			$mode = $this->default_op;
		}
		
		// construct function names for operatio
		$run_mode = 'process_' . $mode;
		$pre_mode = 'on_pre_' . $mode;
		$post_mode = 'on_post_' . $mode;
		$after_mode = 'after_' . $mode;
		$error_mode = 'on_error_' . $mode;
		$key_set_mode = 'get_keys_' . $mode;
		$new_set_mode = 'get_new_' . $mode;
		$old_set_mode = 'get_old_' . $mode;
		$ctl_set_mode = 'get_ctl_' . $mode;		
		$flt_set_mode = 'get_flt_' . $mode;	


	// Populate $this->filters
		if(method_exists($this,$flt_set_mode)){
			$this->$flt_set_mode();
		}
	// Populate $this->keyvalues
		if(method_exists($this,$key_set_mode)){
			$this->$key_set_mode();
		}		
	// Populate $this->newvalues	
		if(method_exists($this,$new_set_mode)){
			$this->$new_set_mode();
		}	
	// Populate $this->oldvalues
		if(method_exists($this,$old_set_mode)){
			$this->$old_set_mode();
		}			
	// Populate $this->ctlvalues
		if(method_exists($this,$ctl_set_mode)){
			$this->$ctl_set_mode();
		}			
	
		// Cleaner functions
		$this->clean_keyvalues();
		$this->clean_newvalues();
		$this->clean_oldvalues();
		$this->clean_ctlvalues();
		
	//	print "<pre>\n Mode: $mode";
	//	print "\nKeyvalues:";
	//	print_r($this->keyvalues);
	//	print "\nNewvalues:";
	//	print_r($this->newvalues);
	//	print "\n</pre>";
	//	exit;


		// Run authorization check
		if(!$this->authorize()){
			$this->unauthorized();
		}
		// pre_action_hook
		$this->on_pre_action();

	
	// User define Pre Mode Action
		if(method_exists($this,$pre_mode)){
			$this->$pre_mode();
		}
	// Run Action	
		if(method_exists($this,$run_mode)){
			$this->$run_mode();
		}	
		
	// Generic post action	
		$this->on_post_action();		
		
	// Run After_mode function or Error (if either defined)	
		if($this->is_error){
			if(method_exists($this,$error_mode)){
			$this->$after_mode();
			}	
		}else{
		
		// User Define Post action	
			if(method_exists($this,$post_mode)){
				$this->$post_mode();
			}		
	
			if(method_exists($this,$after_mode)){
				$this->$after_mode();
			}		
		}

	} // end RunOperation

	
}
	
	
	
 
 

?>
